package com.broada.apm.logic.impl;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.apache.commons.lang.StringUtils;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms.Order;
import org.elasticsearch.search.aggregations.bucket.terms.TermsBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.broada.apm.base.BaseLogic;
import com.broada.apm.entity.OrderClass;
import com.broada.apm.entity.TradePerformance;
import com.broada.apm.indicator.api.common.ApmDataIndicatorException;
import com.broada.apm.indicator.api.model.SearchCondition;
import com.broada.apm.indicator.api.model.SearchConditionComparator;
import com.broada.apm.indicator.api.util.AggregationUtil;
import com.broada.apm.indicator.api.util.DateUtil;
import com.broada.apm.logic.TradePerformanceLogic;
import com.broada.apm.model.BaseResource.RESOURCE_TYPE;
import com.broada.apm.model.ConfigItem;
import com.broada.apm.model.PagingList;
import com.broada.apm.model.PerformanceView;
import com.broada.apm.model.Resource;
import com.broada.apm.model.Service;
import com.broada.apm.utils.ExceptionUtils;
import com.broada.apm.utils.JsonUtil;
import com.google.common.base.Strings;

public class TradePerformanceLogicImpl extends BaseLogic implements TradePerformanceLogic {
	private final static Logger log = LoggerFactory.getLogger(TradePerformanceLogicImpl.class);
//	private static final DateFormat myDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
	private static final String TRANSACTION_TYPE = "tradeTypeName";
	private static final String TRANSACTION_CHANNEL = "tradeChannelName";

	@Override
	public List<PerformanceView> getTradesPerformancesTotal(String appId, String nodeId, String vsite, String orderBy,
			boolean desc, String keyWord, String tradeIp, String tradeProto, Date startDate, Date endDate, int top) {

		SearchCondition con = SearchCondition.newBuilder();
		con.add("timestamp", SearchConditionComparator.LEFTBETWEEN, startDate, endDate);
		con.add("dimensionType", SearchConditionComparator.ISNULL);
		if (StringUtils.isNotBlank(nodeId)) {
			con.add("serviceId", SearchConditionComparator.EQUALS, nodeId);
		}
		if (StringUtils.isNotBlank(vsite)) {
			con.add("domainId", SearchConditionComparator.EQUALS, vsite);
		}
		/*
		 * if (StringUtils.isNotBlank(orderBy)) {
		 * con.setSortField(orderBy).setSortDirection(DESC); }
		 */
		if (StringUtils.isNotBlank(keyWord) || StringUtils.isNotBlank(tradeIp) || StringUtils.isNotBlank(tradeProto)) {
			Resource resource = new Resource();
			// resource.setApplicationId(appId);
			resource.setBelongTo(nodeId);
			resource.setUri(keyWord);
			List<Resource> ress = resourceService.getKeyResourcesByCondition(resource);
			Set<String> resIdSet = new HashSet<String>();
			for (Resource res : ress) {
				resIdSet.add(res.getId());
			}
			con.add("resourceId", SearchConditionComparator.IN, resIdSet.toArray(new String[resIdSet.size()]));
		}
		top = top > 0 ? top : 100;
		// size 分类暂时不会超过100
		TermsBuilder aggs = null;
		if (StringUtils.isBlank(orderBy)) {
			aggs = AggregationUtil.getTerms("resourceId", "resourceId", top);
		} else {
			// 参数要的是asc
			aggs = AggregationUtil.getTerms("resourceId", "resourceId", orderBy, !desc, top);
		}
		aggs.subAggregation(AggregationUtil.getSum("system/throughput/total", "system/throughput/total"));
		aggs.subAggregation(AggregationUtil.getSum("system/response_time/total", "system/response_time/total"));
		aggs.subAggregation(AggregationUtil.getAvg("system/response_time/avg", "system/response_time/avg"));
		aggs.subAggregation(AggregationUtil.getMin("system/response_time/min", "system/response_time/min"));
		aggs.subAggregation(AggregationUtil.getMax("system/response_time/max", "system/response_time/max"));
		aggs.subAggregation(AggregationUtil.getSum("system/request_size/total", "system/request_size/total"));
		aggs.subAggregation(AggregationUtil.getSum("system/error/count", "system/error/count"));
		aggs.subAggregation(AggregationUtil.getSum("system/time/download_time", "system/time/download_time"));
		aggs.subAggregation(AggregationUtil.getSum("system/time/total_time", "system/time/total_time"));
		aggs.subAggregation(AggregationUtil.getSum("system/time/syn_time", "system/time/syn_time"));
		aggs.subAggregation(AggregationUtil.getSum("system/time/request_time", "system/time/request_time"));
		aggs.subAggregation(AggregationUtil.getSum("system/time/server_time", "system/time/server_time"));

		List<PerformanceView> staticPerf = null;
		try {
			staticPerf = queryPerfService.queryAggregationTermsPerf(appId, RESOURCE_TYPE.RESOURCE, con.add(aggs));
		} catch (ApmDataIndicatorException e) {
			ExceptionUtils.error(log, "查询性能数据失败", e);
		}

		return staticPerf;
	}

	@Override
	public List<TradePerformance> getKeyTradePerformanceSubTotal(String appId, String keyWord, Date startDate,
			Date endDate) {
		// 关键交易
		List<Resource> ress = getKeyTradeByCondition(appId, keyWord);
		Set<String> resIdSet = new HashSet<String>();
		for (Resource res : ress) {
			resIdSet.add(res.getId());
		}

		// 交易性能
		List<PerformanceView> staticPerf = getKeyTradePerformanceSubTotal(appId,
				resIdSet.toArray(new String[resIdSet.size()]), startDate, endDate);
		List<TradePerformance> tradePerfs = new ArrayList<TradePerformance>();

		for (Resource res : ress) {// 遍历关键交易，找出对应的性能数据
			PerformanceView performance = null;
			for (PerformanceView perfv : staticPerf) {
				if (res.getId().equals(perfv.getResourceId())) {
					performance = perfv;
					break;
				}
			}
			if (performance == null)
				performance = new PerformanceView();

			if (res.getApdex_t() <= 0) {
				ConfigItem item = configItemService.getConfigItem("basic.apdex_t");
				if (item != null)
					res.setApdex_t(Float.valueOf(item.getValue()));
			}
			Service service = serviceService.getServiceById(res.getApplicationId() + "-" + res.getBelongTo());
			tradePerfs.add(new TradePerformance(res.getName(), res.getId(), res.getUri(),
					(service != null ? service.getIp() : null), (service != null ? service.getProtocol() : null),
					res.getApdex_t(), performance));
		}

		return tradePerfs;
	}

	private List<Resource> getKeyTradeByCondition(String appId, String keyWord) {
		Resource resource = new Resource();
		resource.setApplicationId(appId);
		// resource.setKey(true);
		if (StringUtils.isNotBlank(keyWord)) {
			resource.setUri(keyWord);
		}
		return resourceService.getKeyResourcesByCondition(resource);

	}

	private List<PerformanceView> getKeyTradePerformanceSubTotal(String appId, String[] resourceIds, Date startDate,
			Date endDate) {
		SearchCondition con = SearchCondition.newBuilder();
		con.add("timestamp", SearchConditionComparator.LEFTBETWEEN, startDate, endDate);
		con.add("dimensionType", SearchConditionComparator.ISNULL);
		con.add("resourceId", SearchConditionComparator.IN, resourceIds);
		// size 分类暂时不会超过100
		TermsBuilder aggs = AggregationUtil.getTerms("resourceId", "resourceId", 100);
		aggs.subAggregation(AggregationUtil.getSum("system/throughput/total", "system/throughput/total")); // 吞吐量
		aggs.subAggregation(AggregationUtil.getSum("system/user/unique", "system/user/unique")); // 用户总数
		aggs.subAggregation(AggregationUtil.getAvg("system/score/apdex", "system/score/apdex")); // 应用性能指数
		aggs.subAggregation(AggregationUtil.getSum("system/apdex/unsatisfied", "system/apdex/unsatisfied")); // 不满意的访问数
		aggs.subAggregation(AggregationUtil.getSum("system/user/unsatisfied", "system/user/unsatisfied")); // 受影响的用户数
		aggs.subAggregation(AggregationUtil.getAvg("system/response_time/avg", "system/response_time/avg")); // 响应时间
		aggs.subAggregation(AggregationUtil.getMin("system/response_time/min", "system/response_time/min")); // 最快
		aggs.subAggregation(AggregationUtil.getMax("system/response_time/max", "system/response_time/max")); // 最慢
		aggs.subAggregation(AggregationUtil.getSum("system/request_size/total", "system/request_size/total")); // 页面大小
		aggs.subAggregation(AggregationUtil.getSum("system/error/count", "system/error/count")); // 错误数
		aggs.subAggregation(AggregationUtil.getAvg("system/success/rate", "system/success/rate")); // 成功率

		List<PerformanceView> staticPerf = null;
		try {
			staticPerf = queryPerfService.queryAggregationTermsPerf(appId, RESOURCE_TYPE.KEY_RESOURCE, con.add(aggs));
		} catch (ApmDataIndicatorException e) {
			ExceptionUtils.error(log, "查询性能数据失败", e);
		}

		SearchCondition usersCondition = SearchCondition.newBuilder();
		usersCondition.add("timestamp", SearchConditionComparator.LEFTBETWEEN, startDate, endDate);
		usersCondition.add("resourceId", SearchConditionComparator.IN, resourceIds);
		// size 分类暂时不会超过100
		TermsBuilder usersAggs = AggregationUtil.getTerms("resourceId", "resourceId", 100);
		Set<String> indecis = DateUtil.getDateArray(startDate, endDate, DateUtil.STEP_DAY).stream()
				.map(d -> "apm_data_a" + appId + "_" + new SimpleDateFormat("yyyy_MM_dd").format(d))
				.collect(Collectors.toSet());
		usersAggs.subAggregation(AggregationBuilders.range("unsatisfied").field("unsatisfied").addRange(0.1, 1.1)
				.subAggregation(AggregationBuilders.cardinality("unsatisfied").field("user").precisionThreshold(1000)));
		usersAggs.subAggregation(AggregationBuilders.cardinality("user").field("user").precisionThreshold(1000));

		usersCondition.add(usersAggs);
		try {
			Map<String, PerformanceView> perfmap = staticPerf.stream()
					.collect(Collectors.toMap(PerformanceView::getResourceId, Function.identity()));
			List<PerformanceView> performanceViews = queryPerfService.queryAggregationTermsPerf(appId,
					indecis.toArray(new String[0]), "raw", usersCondition);
			for (Map<String, Object> map : performanceViews) {
				PerformanceView performanceView = perfmap.get(map.get("resourceId"));
				if (performanceView != null) {
					performanceView.put("system/user/unique", map.get("user"));
					performanceView.put("system/user/unsatisfied", map.get("unsatisfied"));
				}
			}
		} catch (ApmDataIndicatorException e) {
			ExceptionUtils.error(log, "查询性能数据失败", e);
		}
		return staticPerf;
	}

	@Override
	public PagingList<PerformanceView> getTrackingTradesPerformances(String applicationId,String agentId, String keyWord,
			String transactionType, String transactionChannel, long startDate, long endDate, int pageIndex, int pageSize, String sortBy,
			boolean desc, String transactionFlag) throws Exception {
		SearchCondition con = SearchCondition.newBuilder();
		con.add("startTime", SearchConditionComparator.LEFTBETWEEN, startDate, endDate);
		con.add("applicationId", SearchConditionComparator.EQUALS, applicationId);
		if(StringUtils.isNotBlank(agentId)){
			con.add("agentId", SearchConditionComparator.EQUALS, agentId);
		}
		if (StringUtils.isNotBlank(transactionType)) {
			con.add("tradeTypeName", SearchConditionComparator.EQUALS, transactionType);
		}
		if (StringUtils.isNotBlank(transactionChannel)) {
			con.add("channelName", SearchConditionComparator.EQUALS, transactionChannel);
		}
		

		if (StringUtils.isNotBlank(keyWord)) {
			SearchCondition searchCondition = SearchCondition.newBuilder();
			searchCondition.addOperator(SearchCondition.SearchConditionOperator.OR);
			searchCondition.add("transactionId", SearchConditionComparator.LIKE, keyWord);
			searchCondition.add("tradeTypeName", SearchConditionComparator.LIKE, keyWord);
			searchCondition.add("remoteAddr", SearchConditionComparator.LIKE, keyWord);
			searchCondition.add("dstIp", SearchConditionComparator.LIKE, keyWord);
			searchCondition.add("endPoint", SearchConditionComparator.LIKE, keyWord);
			if (keyWord.contains("成") || keyWord.contains("功")) {
				if("slow".equals(transactionFlag)){
					con.add("transactionFlag", SearchConditionComparator.EQUALS, "2");
				}else if("default".equals(transactionFlag)){
					con.add("transactionFlag", SearchConditionComparator.IN, new String[]{"2","0"});
				}
			}
			if (keyWord.contains("失") || keyWord.contains("败")) {
				if("error".equals(transactionFlag)){
					con.add("transactionFlag", SearchConditionComparator.IN, new String[]{"1","3"});
				}else if("slow".equals(transactionFlag)){
					con.add("transactionFlag", SearchConditionComparator.IN, new String[]{"3"});
				}
			}
			SearchCondition sc = SearchCondition.newBuilder();
			sc.add("applicationId", SearchConditionComparator.EQUALS, applicationId);
			sc.add("startTime", SearchConditionComparator.LEFTBETWEEN, startDate, endDate);
			sc.add("l7Message", SearchConditionComparator.QUERY_STRING_LIKE, keyWord);
			sc.setPageSize(100);
			List<PerformanceView> transactionDetails = queryPerfService.queryTransactions(sc).getData();
			List<String> transactionIds = new ArrayList<String>();
			for (PerformanceView td : transactionDetails) {
				transactionIds.add(td.get("transactionId").toString());
			}
			if (!transactionIds.isEmpty()) {
				searchCondition.add("id", SearchConditionComparator.IN, transactionIds);
			}

			con.add(searchCondition);
		}else{
			if("error".equals(transactionFlag)){
				con.add("transactionFlag", SearchConditionComparator.IN, new String[]{"1","3"});
			}else if("slow".equals(transactionFlag)){
				con.add("transactionFlag", SearchConditionComparator.IN, new String[]{"2","3"});
			}
		}

		// 默认按开始时间降序排序
		String sortDirection = "asc";
		if (StringUtils.isBlank(sortBy)) {
			sortBy = "startTimeMillion";
		}
		if (desc) {
			sortDirection = "desc";
		}
		con.setSortField(sortBy).setSortDirection(sortDirection).setPageSize(pageSize).setPageIndex(pageIndex);

//		List<PerformanceView> staticPerf = new ArrayList<PerformanceView>();
		PagingList<PerformanceView> page = new PagingList<PerformanceView>();
		try {
			page = queryPerfService.queryTransactions(con);
//			if (!page.isEmpty()) {
//				staticPerf = page.getData();
//			}
		} catch (Exception e) {
			ExceptionUtils.error(log, "查询交易跟踪数据失败", e);
			throw e;
		}

		return page;
	}
	
	@Override
	public List<TradePerformance> tradeAllType(String appId, String agentId,String type, String keyWord, 
			String orderBy, boolean desc, Date startDate, Date endDate, Integer size) throws Exception {
		List<PerformanceView> staticPerf;
		// 交易类型性能
		if("type".equals(type)){
			staticPerf = getTransactionPerformanceSubTotal(appId, agentId, keyWord, orderBy, desc,
					startDate, endDate, TRANSACTION_TYPE, size);
		}else{
			 staticPerf = getTransactionPerformanceSubTotal(appId, agentId, keyWord, orderBy, desc,
					startDate, endDate, TRANSACTION_CHANNEL, size);
		}

		List<TradePerformance> tradePerfs = new ArrayList<TradePerformance>();

		// 这一步其实是多余的，可以考虑去掉，但可能前端也要改
		for (PerformanceView perfv : staticPerf) {
			tradePerfs.add(new TradePerformance(perfv.getTransactionTypeName(), perfv.getResourceId(), perfv.getUri(),
					null, 0, 0f, perfv));
		}
		return tradePerfs;
	}


	private List<PerformanceView> getTransactionPerformanceSubTotal(String appId, String agentId, String keyWord,
			String orderBy, boolean desc, Date startDate, Date endDate, String transaction, Integer size) {
		List<PerformanceView> perfs2 = new ArrayList<PerformanceView>();
		SearchCondition con = SearchCondition.newBuilder();
		con.add("startTime", SearchConditionComparator.LEFTBETWEEN, startDate, endDate);
		con.add("agentId", SearchConditionComparator.EQUALS, agentId);

		TermsBuilder aggs = null;
		if (transaction.equals(TRANSACTION_TYPE)) {
			con.add("tradeTypeName", SearchConditionComparator.EXISTS);
			aggs = AggregationUtil.getTerms("tradeTypeName", "tradeTypeName", size);
		} else {
			con.add("tradeChannelName", SearchConditionComparator.EXISTS);
			aggs = AggregationUtil.getTerms("tradeChannelName", "tradeChannelName", size);
		}
		if (StringUtils.isNotBlank(keyWord)) {
			if (transaction.equals(TRANSACTION_TYPE)) {
			} else {
				con.add("tradeTypeName", SearchConditionComparator.LIKE, keyWord);
				con.add("tradeChannelName", SearchConditionComparator.LIKE, keyWord);
			}
		}

		if (Strings.isNullOrEmpty(orderBy)) {
			orderBy = "business/throughput/total";
			desc = true;
		}

		aggs.subAggregation(AggregationUtil.getCount("business/throughput/total", "_id")); // 交易量
		aggs.subAggregation(AggregationUtil.getSum("business/response_time/total", "elapsed")); // 响应时间
		aggs.subAggregation(AggregationUtil.getFilter("business/error/count", "transactionFlag", new String[]{"1","3"})); // 错误数

		List<PerformanceView> staticPerf = null;
		try {
			staticPerf = queryPerfService.queryAggregationTermsPerf(con.add(aggs));
			for (PerformanceView perf : staticPerf) {
				if (perf.get("business/response_time/total") == null || perf.get("business/throughput/total") == null) {
					continue;
				}
				perf.put("business/response_time/avg",
						Double.parseDouble(perf.get("business/throughput/total").toString()) == 0d ? "-"
								: Double.parseDouble(perf.get("business/response_time/total").toString())
										/ Double.parseDouble(perf.get("business/throughput/total").toString()));
				if (perf.get("business/error/count") == null) {
					continue;
				}
				perf.put("business/success/rate",
						Double.parseDouble(perf.get("business/throughput/total").toString()) == 0d ? "-"
								: (Double.parseDouble(perf.get("business/throughput/total").toString())
										- Double.parseDouble(perf.get("business/error/count").toString()))
										/ Double.parseDouble(perf.get("business/throughput/total").toString()) * 100);
				perf.setServiceId(agentId);
			}
			String orderDirection = "asc";
			if (desc) {
				orderDirection = "desc";
			}
			perfs2 = sortByCondition(staticPerf, orderBy, orderDirection);
		} catch (ApmDataIndicatorException e) {
			ExceptionUtils.error(log, "查询性能数据失败", e);
		}

		return perfs2;
	}

	private List<PerformanceView> sortByCondition(List<PerformanceView> staticPerf, String orderBy,
			String orderDirection) {
		List<OrderClass> list = new ArrayList<OrderClass>();
		List<PerformanceView> staticPerf2 = new ArrayList<PerformanceView>();
		for (int i = 0; i < staticPerf.size(); i++) {
			OrderClass order = new OrderClass();
			PerformanceView performanceView = staticPerf.get(i);
			order.setPerformanceView(performanceView);
			if ("-".equals(performanceView.get(orderBy))) {
				// performanceView.put(orderBy, 0.0);
				order.setOrder(0.0);
			} else {
				order.setOrder(Double.parseDouble(performanceView.get(orderBy).toString()));
			}
			list.add(order);
		}

		if (orderDirection.equals("asc")) {
			Collections.sort(list, new Comparator<OrderClass>() {
				public int compare(OrderClass arg0, OrderClass arg1) {
					return arg0.getOrder().compareTo(arg1.getOrder());
				}
			});
		} else {
			Collections.sort(list, new Comparator<OrderClass>() {
				public int compare(OrderClass arg0, OrderClass arg1) {
					return arg1.getOrder().compareTo(arg0.getOrder());
				}
			});
		}

		for (int i = 0; i < list.size(); i++) {
			OrderClass orderClass = list.get(i);
			staticPerf2.add(i, orderClass.getPerformanceView());
		}
		return staticPerf2;
	}

	@Override
	public List<PerformanceView> getMultiStatistics(Set<String> agentIds, String keyWord, String transactionType,
			String transactionChannel, String dstIp, String srcIp, String responseCode, long startDate, long endDate,
			String sortBy, String groupBy, boolean desc) throws Exception {
		List<PerformanceView> page = new ArrayList<PerformanceView>();
		SearchCondition con = SearchCondition.newBuilder();
		con.add("agentStartTime", SearchConditionComparator.LEFTBETWEEN, startDate, endDate);
		con.add("agentId", SearchConditionComparator.IN, agentIds.toArray(new String[agentIds.size()]));
		con.add("tradeTypeName", SearchConditionComparator.EXISTS);

		if (StringUtils.isNotBlank(transactionType)) {
			con.add("tradeTypeName", SearchConditionComparator.EQUALS, transactionType);
		}
		if (StringUtils.isNotBlank(transactionChannel)) {
			con.add("tradeChannelName", SearchConditionComparator.EQUALS, transactionChannel);
		}
		if (StringUtils.isNotBlank(dstIp)) {
			con.add("endPoint", SearchConditionComparator.EQUALS, dstIp);
		}
		if (StringUtils.isNotBlank(srcIp)) {
			con.add("remoteAddr", SearchConditionComparator.EQUALS, srcIp);
		}
		if (StringUtils.isNotBlank(responseCode)) {
			con.add("returnCode", SearchConditionComparator.EQUALS, responseCode);
		}
		if (StringUtils.isNotBlank(keyWord)) {
			SearchCondition searchCondition = SearchCondition.newBuilder();
			searchCondition.addOperator(SearchCondition.SearchConditionOperator.OR);
			searchCondition.add("tradeTypeName", SearchConditionComparator.LIKE, keyWord);
			searchCondition.add("tradeChannelName", SearchConditionComparator.LIKE, keyWord);
			searchCondition.add("remoteAddr", SearchConditionComparator.LIKE, keyWord);
			searchCondition.add("endPoint", SearchConditionComparator.LIKE, keyWord);
			searchCondition.add("returnCode", SearchConditionComparator.LIKE, keyWord);
			con.add(searchCondition);
		}

		// 按传进来的字段进行分组
		TermsBuilder aggs = AggregationUtil.getTerms(groupBy, groupBy, 100);
		aggs.subAggregation(AggregationUtil.getCount("business/throughput/total", "_index")); // 交易量
		aggs.subAggregation(AggregationUtil.getAvg("business/response_time/avg", "elapsed")); // 响应时间
		aggs.subAggregation(AggregationUtil.getFilter("isError", "transactionFlag", new String[]{"1", "3"})); // 错误数
		aggs.subAggregation(AggregationUtil.getTerms("typeName", "tradeTypeName"));
		if(!Strings.isNullOrEmpty(sortBy)){
			if ("business/success/rate".equals(sortBy)) {
				aggs.order(Order.compound(Order.aggregation("business/throughput/total", !desc), Order.aggregation("isError", desc)));
			} else {
				aggs.order(Order.aggregation(sortBy, !desc));
			}
		} else {
			aggs.order(Order.aggregation("business/throughput/total", desc));
		}
		con.add(aggs);
		
		try {
			page = queryPerfService.queryAggregationTermsPerf(con);
			if (!page.isEmpty()) {
				for (PerformanceView pv : page) {
					double total = Double.parseDouble(String.valueOf(pv.get("business/throughput/total")));
					double error = Double.parseDouble(String.valueOf(pv.get("isError")));
					if (total == 0d) {
						pv.put("business/success/rate", "-");
					} else {
						double successRate = (total - error) * 100 / total;
						pv.put("business/success/rate",
								new BigDecimal(successRate).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
					}
				}
			}
		} catch (Exception e) {
			ExceptionUtils.error(log, "查询交易跟踪数据失败", e);
			throw e;
		}
		return page;
	}

	@SuppressWarnings("unchecked")
	@Override
	public PerformanceView transactionDetail(String spanId, long startDate, long endDate) throws Exception {
		SearchCondition con = SearchCondition.newBuilder();
		con.add("agentStartTime", SearchConditionComparator.LEFTBETWEEN, startDate, endDate);
		con.add("spanId", SearchConditionComparator.EQUALS, spanId);
		List<PerformanceView> transactionDetail = queryPerfService.queryPerformanceDetail(con);
		if (transactionDetail != null && !transactionDetail.isEmpty()) {
			PerformanceView pv = transactionDetail.get(0);
			TreeMap<String, Object> map = (TreeMap<String, Object>) JsonUtil.json2obj(pv.get("l7Message").toString(),
					TreeMap.class);
			if (map != null)
				pv.setFields(map);
			return pv;
		}
		return null;
	}

	@Override
	public List<PerformanceView> getHttpSlowSort(String appId, int top, Date startDate, Date endDate) {
		List<PerformanceView> result = new ArrayList<PerformanceView>();
		List<PerformanceView> ret = new ArrayList<PerformanceView>();
		SearchCondition con = SearchCondition.newBuilder();
		List<Service> services = serviceService.getServicesByAppId(appId);
		List<String> serviceIds = new ArrayList<String>();
		if(services != null && services.size() > 0){
			for(Service service : services){
				if(service.getAutoDiscoveryProtocol() == 80) {
					serviceIds.add(service.getId());
				}
			}
		}
		Object[] serviceId_arry = new String[serviceIds.size()];
		if(serviceIds.size() > 0){
			serviceId_arry = serviceIds.toArray();
			con.add("serviceId", SearchConditionComparator.IN, serviceId_arry);
		}else{
			return result;
		}
		con.add("timestamp", SearchConditionComparator.LEFTBETWEEN, startDate, endDate);
		con.add("domainId", SearchConditionComparator.EXISTS);
		con.add("dimensionType", SearchConditionComparator.ISNULL);
		con.add("key", SearchConditionComparator.EQUALS, "false");
		TermsBuilder tb = AggregationUtil.getTerms("resourceId", "resourceId", 0);
//		tb.subAggregation(AggregationUtil.getAvg("system/response_time/avg", "system/response_time/avg"));
		tb.order(Order.compound(Order.aggregation("system/response_time/total", false), Order.aggregation("system/throughput/total", true)));
//		TermsBuilder tb = AggregationUtil.getTerms("uri", "uri", 100);
		//Domain
		TermsBuilder tb2 = AggregationUtil.getTerms("domainId", "domainId", 0);
		//最大响应时间
		tb.subAggregation(AggregationUtil.getMax("system/response_time/max", "system/response_time/max"));
		//最小响应时间
		tb.subAggregation(AggregationUtil.getMin("system/response_time/min", "system/response_time/min"));
		// 运行总时长/吞吐量  = 平均响应时间
		tb.subAggregation(AggregationUtil.getSum("system/response_time/total", "system/response_time/total"));
		tb.subAggregation(AggregationUtil.getSum("system/throughput/total", "system/throughput/total"));
		// 访问次数  - 体验好的  - 体验容忍  - 错误数  = 慢交易数
		// 体验好的
		tb.subAggregation(AggregationUtil.getSum("system/apdex/satisfied", "system/apdex/satisfied"));
		// 体验容忍
		tb.subAggregation(AggregationUtil.getSum("system/apdex/tolerate", "system/apdex/tolerate"));
		// 错误数
		tb.subAggregation(AggregationUtil.getSum("system/error/count", "system/error/count"));
		// 按平均响应时间降序排序
//		tb2.subAggregation(AggregationUtil.getAvg("system/response_time/avg", "system/response_time/avg"));
//		tb2.order(Order.compound(Order.aggregation("system/response_time/avg", false)));
		tb.subAggregation(tb2);
		try {
			long startTime = System.currentTimeMillis();
			result = queryPerfService.queryAggregationTermsPerf(appId, RESOURCE_TYPE.RESOURCE, con.add(tb));
			log.error("最慢HTTP排行ES查询用时：" + (System.currentTimeMillis() - startTime));
			//排序
			List<OrderClass> orders = new ArrayList<OrderClass>();
			// 完整数据
			if(result.size() > 0){
				startTime = System.currentTimeMillis();
				for(PerformanceView pv : result){
					// 设置uri
					Resource resource = resourceService.getResourceById(pv.get("resourceId").toString());
					if(resource == null){
						continue;
					}
					if(pv.get("system/response_time/total").toString() != null 
							&& pv.get("system/throughput/total").toString() != null){
						// 计算系统平均响应时间
						pv.put("system/response_time/avg", 
								Double.valueOf(pv.get("system/throughput/total").toString()) == 0d? "-":
									BigDecimal.valueOf((Double.valueOf(pv.get("system/response_time/total").toString())
											            /Double.valueOf(pv.get("system/throughput/total").toString()))/1000)
									.setScale(2, BigDecimal.ROUND_DOWN).doubleValue());
					}else{
						pv.put("system/response_time/avg", BigDecimal.valueOf(0l)
								   .setScale(2, BigDecimal.ROUND_DOWN).doubleValue());
					}
					
					if(pv.get("system/response_time/max")!= null){
						pv.put("system/response_time/max", BigDecimal.valueOf(Double.valueOf(pv.get("system/response_time/max").toString())/1000)
														   .setScale(2, BigDecimal.ROUND_DOWN).doubleValue());
					}else{
						pv.put("system/response_time/max","-");
					}
					
					if(pv.get("system/response_time/min")!= null){
						pv.put("system/response_time/min", BigDecimal.valueOf(Double.valueOf(pv.get("system/response_time/min").toString())/1000)
								.setScale(2, BigDecimal.ROUND_DOWN).doubleValue());
					}else{
						pv.put("system/response_time/min","-");
					}
					
					if(pv.get("system/response_time/total")!= null){
						pv.put("system/response_time/total", BigDecimal.valueOf(Double.valueOf(pv.get("system/response_time/total").toString())/1000)
								.setScale(2, BigDecimal.ROUND_DOWN).doubleValue());
					}else{
						pv.put("system/response_time/total","-");
					}
					
					double val = Double.valueOf(pv.get("system/throughput/total") == null? "0" : pv.get("system/throughput/total").toString()) 
							- Double.valueOf(pv.get("system/apdex/satisfied") == null? "0" : pv.get("system/apdex/satisfied").toString())
							- Double.valueOf(pv.get("system/apdex/tolerate") == null? "0" : pv.get("system/apdex/tolerate").toString())
							- Double.valueOf(pv.get("system/error/count") == null? "0" : pv.get("system/error/count").toString());
					pv.put("system/apdex/slow",val < 0d? "-" : val);
					
					pv.put("resourceId", resource.getUri());
					OrderClass clazz = new OrderClass();
					clazz.setPerformanceView(pv);
					clazz.setOrder(Double.valueOf(pv.get("system/response_time/avg").toString().equals("-")? "0" : pv.get("system/response_time/avg").toString()));
					orders.add(clazz);
				}
				log.error("最慢HTTP排行循环用时：" + (System.currentTimeMillis() - startTime));
			}
			if(orders.size() > 0){  //平均响应时间降序排序
				Collections.sort(orders, new Comparator<OrderClass>() {
					@Override
					public int compare(OrderClass o1, OrderClass o2) {
						return o2.getOrder().compareTo(o1.getOrder());
					}
				});
				for(OrderClass clazz : orders){
					ret.add(clazz.getPerformanceView());
				}
			}
			if(ret.size() > top){
				ret = ret.subList(0, top);
			}
		} catch (ApmDataIndicatorException e) {
			log.error("查询性能数据失败：" + e.getMessage());
		}
		return ret;
	}

	@Override
	public List<PerformanceView> getHttpErrorSort(String appId, int top, Date startDate, Date endDate) {
		List<PerformanceView> result = new ArrayList<PerformanceView>();
		SearchCondition con = SearchCondition.newBuilder();
		List<Service> services = serviceService.getServicesByAppId(appId);
		List<String> serviceIds = new ArrayList<String>();
		if(services != null && services.size() > 0){
			for(Service service : services){
				if(service.getAutoDiscoveryProtocol() == 80) {
					serviceIds.add(service.getId());
				}
			}
		}
		Object[] serviceId_arry = new String[serviceIds.size()];
		if(serviceIds.size() > 0){
			serviceId_arry = serviceIds.toArray();
			con.add("serviceId", SearchConditionComparator.IN, serviceId_arry);
		}else{
			return result;
		}
		con.add("timestamp", SearchConditionComparator.LEFTBETWEEN, startDate, endDate);
		con.add("dimensionType", SearchConditionComparator.EQUALS, "error");
		con.add("key", SearchConditionComparator.EQUALS, "false");
		TermsBuilder tb = AggregationUtil.getTerms("resourceId", "resourceId", 0);
		tb.subAggregation(AggregationUtil.getSum("system/throughput/total", "system/throughput/total"));     // 总吞吐量
		tb.subAggregation(AggregationUtil.getSum("system/error/count", "system/error/count"));  // 总错误数
		tb.order(Order.compound(Order.aggregation("system/throughput/total", false), Order.aggregation("system/error/count", true)));
		TermsBuilder tb2 = AggregationUtil.getTerms("domainId", "domainId", 0);
		TermsBuilder tb3 = AggregationUtil.getTerms("dimensionId", "dimensionId", 0);
		tb3.subAggregation(AggregationUtil.getSum("count", "system/error/count"));
		tb2.subAggregation(tb3);
		tb.subAggregation(tb2);
		
		List<PerformanceView> perfs = new ArrayList<PerformanceView>();
		try {
			long startTime = System.currentTimeMillis();
			result = queryPerfService.queryErrorTermsPerf(appId, RESOURCE_TYPE.RESOURCE, con.add(tb));
			log.error("错误HTTP排行ES查询用时：" + (System.currentTimeMillis() - startTime));
			//排序
			List<OrderClass> orders = new ArrayList<OrderClass>();
			if(result.size() > 0){
				startTime = System.currentTimeMillis();
				for(PerformanceView pv : result){   // 过滤出以3xx,4xx,5xx开头的返回码
					// 设置uri 
					Resource resource = resourceService.getResourceById(pv.get("resourceId").toString());
					if(resource == null){
						continue;
					}
					// 计算成功率
					computeSuccessRate(pv);
					if(pv.get("system/success/rate").toString().startsWith("100")){
						continue;   // 成功率为100的过滤
					}
					if(!pv.get("dimensionId").toString().startsWith("3") && 
					   !pv.get("dimensionId").toString().startsWith("4") &&
					   !pv.get("dimensionId").toString().startsWith("5")){
						continue;
					}
					pv.put("system/throughput/total", Double.valueOf(pv.get("system/throughput/total").toString()).longValue());   // 吞吐量处理
					pv.put("resourceId", resource.getUri());
					perfs.add(pv);
				}
				log.error("错误HTTP排行循环用时：" + (System.currentTimeMillis() - startTime));
			}
			result = null;
			if(perfs.size() > 0){
				result = totalHttpPerformanceView(perfs);
				perfs.clear();
			}
			if(result != null && result.size() > 0){
				 for(PerformanceView perf : result){
					 long xx3 = 0, xx4 = 0, xx5 = 0;
					 @SuppressWarnings("unchecked")
					 List<Map<String, Object>> list = (List<Map<String, Object>>) perf.get("dimensionId");
					 perf.get("resourceId");
					 if(list != null && list.size() > 0){
						 for(Map<String, Object> map:list){
							 String dimensionId = map.get("dimensionId").toString();
							 String flag = dimensionId.substring(dimensionId.indexOf('.') + 1, dimensionId.length());
							 if(flag.startsWith("3")){
								 xx3 += Double.valueOf(map.get("count").toString());
							 }else if(flag.startsWith("4")){
								 xx4 += Double.valueOf(map.get("count").toString());
							 }else if(flag.startsWith("5")){
								 xx5 += Double.valueOf(map.get("count").toString());
							 }
						 }
					 }
					 perf.put("3xx", xx3);
					 perf.put("4xx", xx4);
					 perf.put("5xx", xx5);
					 perfs.add(perf);
				 }
			}
			if(result != null && result.size() > 0){
				for(PerformanceView pv:result){
					//按成功率排序
					OrderClass clazz = new OrderClass();
					clazz.setPerformanceView(pv);
					clazz.setOrder(Double.valueOf(pv.get("system/success/rate").toString()));
					orders.add(clazz);
				}
				result.clear();
				perfs.clear();
			}
			if(orders.size() > 0){  // 成功率升序
				startTime = System.currentTimeMillis();
				Collections.sort(orders, new Comparator<OrderClass>() {
					@Override
					public int compare(OrderClass o1, OrderClass o2) {
						return o1.getOrder().compareTo(o2.getOrder());
					}
				});
				for(OrderClass clazz : orders){
					perfs.add(clazz.getPerformanceView());
				}
				log.error("错误HTTP排行排序用时：" + (System.currentTimeMillis() - startTime));
			}
			if(perfs.size() > top){
				perfs = perfs.subList(0, top);
			}
		} catch (ApmDataIndicatorException e) {
			log.error("查询性能数据失败：" + e.getMessage());
		}
		return perfs;
	}

	@Override
	public List<PerformanceView> getSqlSlowSort(String appId, int top, Date startDate, Date endDate) {
		List<PerformanceView> perfs = new ArrayList<PerformanceView>();    // 返回结果
		List<PerformanceView> result = new ArrayList<PerformanceView>();   // 中间处理结果
		List<Service> services = serviceService.getServicesByAppId(appId);
		List<String> serviceIds = new ArrayList<String>();
		if(services != null && services.size() > 0){
			for(Service service : services){
				if(isDataBaseType(service.getAutoDiscoveryProtocol())) {
					serviceIds.add(service.getId());
				}
			}
		}
		SearchCondition con = SearchCondition.newBuilder();
		con.add("timestamp", SearchConditionComparator.LEFTBETWEEN, startDate, endDate);
		con.add("dimensionType", SearchConditionComparator.ISNULL);
		
		Object[] serviceId_arry = new String[serviceIds.size()];
		if(serviceIds.size() > 0){
			serviceId_arry = serviceIds.toArray();
			con.add("serviceId", SearchConditionComparator.IN, serviceId_arry);
		}else{
			return result;
		}
		TermsBuilder tb = AggregationUtil.getTerms("resourceId", "resourceId", 0);
		tb.subAggregation(AggregationUtil.getMax("system/response_time/max", "system/response_time/max"));  // 最大响应时间
		tb.subAggregation(AggregationUtil.getMin("system/response_time/min", "system/response_time/min"));  // 最小响应时间
		tb.subAggregation(AggregationUtil.getSum("system/response_time/total", "system/response_time/total"));   // 运行总时长
		tb.subAggregation(AggregationUtil.getSum("system/throughput/total", "system/throughput/total"));    // 总吞吐量(调用次数)
		tb.subAggregation(AggregationUtil.getAvg("system/response_time/avg", "system/response_time/avg"));
		tb.order(Order.compound(Order.aggregation("system/response_time/total", false), Order.aggregation("system/throughput/total", true)));
		try {
			long startTime = System.currentTimeMillis();
			result = queryPerfService.queryAggregationTermsPerf(appId, RESOURCE_TYPE.RESOURCE, con.add(tb));
			log.error("最慢SQL排行ES查询用时：" + (System.currentTimeMillis() - startTime));
			List<OrderClass> orders = new ArrayList<OrderClass>();
			if(result.size() > 0){
				//计算平均响应时间
				startTime = System.currentTimeMillis();
				for(PerformanceView pv : result){
					
					// 设置sql语句
					Resource resource = resourceService.getResourceById(pv.get("resourceId").toString());
					if(resource == null){
						continue;
					}
					if(pv.get("system/throughput/total").toString() != null 
							&& pv.get("system/response_time/total").toString() != null
							&& Double.valueOf(pv.get("system/response_time/total").toString()).doubleValue() != 0d){
						pv.put("system/response_time/avg", BigDecimal.valueOf(Double.valueOf(pv.get("system/response_time/total").toString())
								                                              / Double.valueOf(pv.get("system/throughput/total").toString()) / 1000)
								.setScale(2, BigDecimal.ROUND_DOWN).doubleValue());
					}else{
						pv.put("system/response_time/avg", BigDecimal.valueOf(0l).setScale(2, BigDecimal.ROUND_DOWN).doubleValue());
					}
					
					if(pv.get("system/response_time/max") != null){
						pv.put("system/response_time/max", BigDecimal.valueOf(Double.valueOf(pv.get("system/response_time/max").toString()) / 1000)
								.setScale(2, BigDecimal.ROUND_DOWN).doubleValue());
					}else{
						pv.put("system/response_time/max", "-");
					}
					
					if(pv.get("system/response_time/min") != null){
						pv.put("system/response_time/min", BigDecimal.valueOf(Double.valueOf(pv.get("system/response_time/min").toString()) / 1000)
								.setScale(2, BigDecimal.ROUND_DOWN).doubleValue());
					}else{
						pv.put("system/response_time/min", "-");
					}
					
					if(pv.get("system/response_time/total") != null){
						pv.put("system/response_time/total", BigDecimal.valueOf(Double.valueOf(pv.get("system/response_time/total").toString()) / 1000)
								.setScale(2, BigDecimal.ROUND_DOWN).doubleValue());
					}else{
						pv.put("system/response_time/total", "-");
					}
					pv.put("resourceId", resource.getUri());
					pv.put("system/throughput/total", (long)Double.parseDouble(pv.get("system/throughput/total").toString()));
					OrderClass clazz = new OrderClass();
					clazz.setPerformanceView(pv);
					clazz.setOrder(Double.valueOf(pv.get("system/response_time/avg").toString()));
					orders.add(clazz);
				}
				log.error("最慢SQL排行循环用时：" + (System.currentTimeMillis() - startTime));
			}
			if(orders.size() > 0){
				startTime = System.currentTimeMillis();
				Collections.sort(orders, new Comparator<OrderClass>() {
					@Override
					public int compare(OrderClass o1, OrderClass o2) {
						return o2.getOrder().compareTo(o1.getOrder());  //平均响应时间按降序排序
					}
				});
				for(OrderClass clazz : orders){
					perfs.add(clazz.getPerformanceView());
				}
				log.error("最慢SQL排行排序用时：" + (System.currentTimeMillis() - startTime));
			}
			if(perfs.size() > top){
				perfs = perfs.subList(0, top);
			}
		} catch (ApmDataIndicatorException e) {
			log.error("查询性能数据失败：" + e.getMessage());
		}
		return perfs;
	}

	@Override
	public List<PerformanceView> getSqlErrorSort(String appId, int top, Date startDate, Date endDate) {
		List<PerformanceView> perfs = new ArrayList<PerformanceView>();    // 返回结果
		List<PerformanceView> result = new ArrayList<PerformanceView>();   // 中间处理结果
		List<Service> services = serviceService.getServicesByAppId(appId);
		List<String> serviceIds = new ArrayList<String>();
		if(services != null && services.size() > 0){
			for(Service service : services){
				if(isDataBaseType(service.getAutoDiscoveryProtocol())) {
					serviceIds.add(service.getId());
				}
			}
		}
		SearchCondition con = SearchCondition.newBuilder();
		con.add("timestamp", SearchConditionComparator.LEFTBETWEEN, startDate, endDate);
		con.add("dimensionType", SearchConditionComparator.EQUALS, "error");
		con.add("key", SearchConditionComparator.EQUALS, "false");
		Object[] serviceId_arry = new Object[serviceIds.size()];
		if(serviceIds.size() > 0){
			serviceId_arry =  serviceIds.toArray();
			con.add("serviceId", SearchConditionComparator.IN, serviceId_arry);
		}else{
			return result;
		}
		TermsBuilder tb = AggregationUtil.getTerms("resourceId", "resourceId", 0);
		tb.subAggregation(AggregationUtil.getSum("system/throughput/total", "system/throughput/total"));   // 总调用次数
		tb.subAggregation(AggregationUtil.getSum("system/error/count", "system/error/count"));   // 总错误数
		
//		TermsBuilder tb2 = AggregationUtil.getTerms("dimensionId", "dimensionId", 3);
//		tb2.subAggregation(AggregationUtil.getSum("count", "system/error/count"));
//		tb2.order(Order.compound(Order.aggregation("count", false)));
//		tb.subAggregation(tb2);
		//排序
		List<OrderClass> orders = new ArrayList<OrderClass>();
		try {
			long startTime = System.currentTimeMillis();
			result = queryPerfService.queryErrorTermsPerf(appId, RESOURCE_TYPE.RESOURCE, con.add(tb));
			log.error("错误SQL排行ES查询用时：" + (System.currentTimeMillis() - startTime));
			if(result.size() > 0){   // 计算成功率，匹配uri，过滤
				startTime = System.currentTimeMillis();
				for(PerformanceView pv : result){
					// 设置sql语句
					Resource resource = resourceService.getResourceById(pv.get("resourceId").toString());
					if(resource == null){
						continue;
					}
					computeSuccessRate(pv);
					if(pv.get("system/success/rate").toString().startsWith("100")){
						continue;   // 成功率为100的过滤
					}
					pv.put("resourceId", resource.getUri());
					pv.put("system/throughput/total", Double.valueOf(pv.get("system/throughput/total").toString()).intValue());   // 吞吐量处理
					pv.put("system/error/count", Double.valueOf(pv.get("system/error/count").toString()).intValue());   // 吞吐量处理
					perfs.add(pv);
				}
				log.error("错误SQL排行循环用时：" + (System.currentTimeMillis() - startTime));
			}
//			result = null;
//			if(perfs != null && perfs.size() > 0){
//				result = totalSqlPerformanceView(perfs);
//				perfs.clear();
//			}
			if(perfs != null && perfs.size() > 0){
				for(PerformanceView pv : perfs){
					//按成功率排序
					OrderClass clazz = new OrderClass();
					clazz.setPerformanceView(pv);
					clazz.setOrder(Double.valueOf(pv.get("system/success/rate").toString()));
					orders.add(clazz);
				}
				perfs.clear();
			}
			if(orders.size() > 0){  // 成功率升序
				startTime = System.currentTimeMillis();
				Collections.sort(orders, new Comparator<OrderClass>() {
					@Override
					public int compare(OrderClass o1, OrderClass o2) {
						return o1.getOrder().compareTo(o2.getOrder());
					}
				});
				for(OrderClass clazz : orders){
					perfs.add(clazz.getPerformanceView());
				}
				log.error("错误SQL排行排序用时：" + (System.currentTimeMillis() - startTime));
			}
			if(perfs.size() > top){
				perfs = perfs.subList(0, top);
			}
		} catch (ApmDataIndicatorException e) {
			log.error("查询性能数据失败：" + e.getMessage());
		}
		return perfs;
	}
	
	

	
	/**
	 * 判断是否是数据库类型的协议
	 * @param protocol
	 * @return
	 */
	private boolean isDataBaseType(int protocol){
		if(protocol == 1433
			||protocol == 1521
			||protocol == 50000
			||protocol == 5000
			||protocol == 3306
			||protocol == 9088
			||protocol == 11211
			||protocol == 6379
			||protocol == 27017
			||protocol == 5432
			||protocol == 9160){
			return true;
		}else{
			return false;
		}
	}
	
	/**
	 * 查询http错误
	 * @param appId
	 * @param pv
	 * @param startDate
	 * @param endDate
	 * @return
	 */
	@SuppressWarnings("unused")
	private PerformanceView queryHttpError(String appId, PerformanceView pv, Date startDate, Date endDate, Object[] array){
		SearchCondition condition = SearchCondition.newBuilder();
		condition.add("timestamp", SearchConditionComparator.LEFTBETWEEN, startDate, endDate);
		condition.add("domainId", SearchConditionComparator.EQUALS, pv.get("domainId").toString());
		condition.add("resourceId", SearchConditionComparator.EQUALS, pv.get("resourceId").toString());
		condition.add("serviceId", SearchConditionComparator.IN, array);
		TermsBuilder tb = AggregationUtil.getTerms("dimensionId", "dimensionId", 0);
		tb.subAggregation(AggregationUtil.getSum("count", "system/error/count"));
		List<PerformanceView> ret_pvs = new ArrayList<PerformanceView>();
		try {
//			ret_pvs = errorRecordService.queryAggregationTermsErrorRedord(appId, condition.add(tb));
			ret_pvs = queryPerfService.queryAggregationTermsPerf(appId, RESOURCE_TYPE.RESOURCE, condition.add(tb));
			if(ret_pvs != null && ret_pvs.size() > 0){
				 double xx3 = 0, xx4 = 0, xx5 = 0;
				 for(PerformanceView perf : ret_pvs){
					 String dimensionId = perf.get("dimensionId").toString();
					 String flag = dimensionId.substring(dimensionId.indexOf('.') + 1, dimensionId.length());
					 if(flag.startsWith("3")){
						 xx3 += Double.valueOf(perf.get("count").toString());
					 }else if(flag.startsWith("4")){
						 xx4 += Double.valueOf(perf.get("count").toString());
					 }else if(flag.startsWith("5")){
						 xx5 += Double.valueOf(perf.get("count").toString());
					 }
				 }
				 pv.put("3xx", xx3);
				 pv.put("4xx", xx4);
				 pv.put("5xx", xx5);
			}
		} catch (ApmDataIndicatorException e) {
			log.error("查询性能数据失败：" + e.getMessage());
		}
		return pv;
	}
	
	/**
	 * 查询sql错误
	 * @param appId
	 * @param pv
	 * @param startDate
	 * @param endDate
	 * @return
	 */
	@SuppressWarnings("unused")
	private PerformanceView querySqlError(String appId, PerformanceView pv, Date startDate, Date endDate, Object[] array){
		SearchCondition con2 = SearchCondition.newBuilder();
		con2.add("timestamp", SearchConditionComparator.LEFTBETWEEN, startDate, endDate);
		con2.add("serviceId", SearchConditionComparator.IN, array);
		con2.add("dimensionType", SearchConditionComparator.EQUALS, "error");
		con2.add("resourceId", SearchConditionComparator.EQUALS, pv.get("resourceId"));
		TermsBuilder tb2 = AggregationUtil.getTerms("dimensionId", "dimensionId", 3);
		tb2.subAggregation(AggregationUtil.getSum("count", "system/error/count"));
		tb2.order(Order.compound(Order.aggregation("count", false)));
		con2.add(tb2);
		List<PerformanceView> ret_pvs = new ArrayList<PerformanceView>();
		List<Map<String, Object>> rets = new ArrayList<Map<String, Object>>();
		try {
			ret_pvs = queryPerfService.queryAggregationTermsPerf(appId, RESOURCE_TYPE.RESOURCE, con2);
//			ret_pvs = errorRecordService.queryAggregationTermsErrorRedord(appId, con2);
			if(ret_pvs != null && ret_pvs.size() > 0){
				for(PerformanceView pv1 : ret_pvs){
//					Map<String, Object> map = new HashMap<String, Object>();
//					for(Object obj:array){
//						String serviceId = obj.toString();
//						Service service = serviceService.getServiceById(serviceId);
//						if(service != null){
//							Dimension.Error error = dimensionService.getErrorById(pv1.get("dimensionId").toString());
//							map.put("dimensionId", error.getCode());
//						}
//					}
					String dimensionId = pv1.get("dimensionId").toString();
					String flag = dimensionId.substring(dimensionId.indexOf('.') + 1, dimensionId.length());
					pv1.put("dimensionId", flag);
					rets.add(pv1);
				}
				pv.put("dimensionId", rets);
			}
		} catch (ApmDataIndicatorException e) {
			log.error("查询性能数据失败：" + e.getMessage());
		}
		return pv;
	}

	@Override
	public List<PerformanceView> getTradeMergeByStability(String termBy, Date startDate, Date endDate) {
		List<PerformanceView> result = new ArrayList<PerformanceView>();
		SearchCondition con = SearchCondition.newBuilder();
		con.add("startTime", SearchConditionComparator.LEFTBETWEEN, startDate, endDate);

		TermsBuilder tb = null;
		if ("stability_level1".equals(termBy) || "scale_level1".equals(termBy)) {
			tb = AggregationUtil.getTerms(termBy, termBy, Integer.MAX_VALUE);
			tb.subAggregation(AggregationUtil.getCount("count", "_index")); // 交易量
			tb.subAggregation(AggregationUtil.getFilter("isError", "isError", "true")); // 错误数
		} else if ("stability_level2".equals(termBy)) {
			tb = AggregationUtil.getTerms("stability_level1", "stability_level1", Integer.MAX_VALUE);
			TermsBuilder tb2 = AggregationUtil.getTerms("stability_level2", "stability_level2");
			tb2.subAggregation(AggregationUtil.getCount("count", "_index")); // 交易量
			tb2.subAggregation(AggregationUtil.getFilter("isError", "isError", "true")); // 错误数
			tb.subAggregation(tb2);
		}
		
		PagingList<PerformanceView> page = null;
		try {
			page = queryPerfService.queryTermsCount(con.add(tb));
		} catch (ApmDataIndicatorException e) {
			log.error("查询性能数据失败：" + e.getMessage());
		}
		if (page != null ) {
			result = page.getData();
		}
		
		return result;
	}
	
	/**
	 * 计算成功率
	 * @param pv
	 */
	private void computeSuccessRate(PerformanceView pv){
		if(pv.get("system/throughput/total") != null && pv.get("system/error/count") != null &&
		   StringUtils.isNotBlank(pv.get("system/throughput/total").toString()) && 
		   StringUtils.isNotBlank(pv.get("system/error/count").toString())){
			double visit_total = Double.valueOf(pv.get("system/throughput/total").toString());
			double error_total = Double.valueOf(pv.get("system/error/count").toString());
			if(visit_total == 0d){
				pv.put("system/success/rate", BigDecimal.valueOf(0l).setScale(2, BigDecimal.ROUND_DOWN).doubleValue());
			}
			else{
				pv.put("system/success/rate", BigDecimal.valueOf((visit_total - error_total) / visit_total * 100).setScale(2, BigDecimal.ROUND_DOWN).doubleValue());
			}
		}
	}

	
	/**
	 * 归并嵌套Terms查询结果
	 * @param perfs
	 * @return
	 */
	@SuppressWarnings("unused")
	private List<PerformanceView> totalSqlPerformanceView(List<PerformanceView> perfs){
		List<PerformanceView> result = new ArrayList<PerformanceView>();
		boolean end = false;
		for(int i=0; i<perfs.size(); i++){
			if(end == true){
				return result;
			}
			List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
			PerformanceView pv = new PerformanceView();
			String resourceId_i = perfs.get(i).get("resourceId").toString();
			int last=0;
			for(int j=i; j<perfs.size(); j++){
				last = j;
				String resourceId_j = perfs.get(j).get("resourceId").toString();
				if(pv.get("resourceId") != null){
					if(resourceId_i.equals(resourceId_j)){
						// 已经存在
						if(perfs.get(j).get("dimensionId")!=null){
							Map<String, Object> next = new HashMap<String, Object>();
							next.put("dimensionId", perfs.get(j).get("dimensionId").toString());
							next.put("count", perfs.get(j).get("count"));
							list.add(next);
						}
					}else{
						i = j - 1;
						pv.put("dimensionId", list);
						break;
					}
				}else{
					// 尚未存在
					pv.put("resourceId", resourceId_j);    // uri
					pv.put("system/throughput/total", perfs.get(j).get("system/throughput/total").toString());   // 总次数
					pv.put("system/error/count", perfs.get(j).get("system/error/count").toString());             // 总错误数
					pv.put("system/success/rate", perfs.get(j).get("system/success/rate").toString());           // 成功率
					Map<String, Object> first = new HashMap<String, Object>();
					first.put("dimensionId", perfs.get(j).get("dimensionId").toString());
					first.put("count", perfs.get(j).get("count"));
					list.add(first);
				}
			}
			if(last == perfs.size()-1){
				pv.put("dimensionId", list);
				end = true;
			}
			result.add(pv);
		}
		return result;
	}
	
	private List<PerformanceView> totalHttpPerformanceView(List<PerformanceView> perfs){
		List<PerformanceView> result = new ArrayList<PerformanceView>();
		boolean end = false;
		for(int i=0; i<perfs.size(); i++){
			if(end == true){
				return result;
			}
			List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
			PerformanceView pv = new PerformanceView();
			String resourceId_i = perfs.get(i).get("resourceId").toString();
			int last=0;
			for(int j=i; j<perfs.size(); j++){
				last = j;
				String resourceId_j = perfs.get(j).get("resourceId").toString();
				if(pv.get("resourceId") != null){
					if(resourceId_i.equals(resourceId_j)){
						// 已经存在
						if(perfs.get(j).get("dimensionId")!=null){
							Map<String, Object> next = new HashMap<String, Object>();
							next.put("dimensionId", perfs.get(j).get("dimensionId").toString());
							next.put("count", perfs.get(j).get("count"));
							list.add(next);
						}
					}else{
						i = j - 1;
						pv.put("dimensionId", list);
						break;
					}
				}else{
					// 尚未存在
					pv.put("resourceId", resourceId_j);    // uri
					pv.put("domainId", perfs.get(j).get("domainId").toString());
					pv.put("system/throughput/total", perfs.get(j).get("system/throughput/total").toString());   // 总次数
					pv.put("system/error/count", perfs.get(j).get("system/error/count").toString());             // 总错误数
					pv.put("system/success/rate", perfs.get(j).get("system/success/rate").toString());           // 成功率
					Map<String, Object> first = new HashMap<String, Object>();
					first.put("dimensionId", perfs.get(j).get("dimensionId").toString());
					first.put("count", perfs.get(j).get("count"));
					list.add(first);
				}
			}
			if(last == perfs.size()-1){
				pv.put("dimensionId", list);
				end = true;
			}
			result.add(pv);
		}
		return result;
	}


	@Override
	public List<PerformanceView> getChannelAndTypeByService(String applicationId, Set<String> serviceIds, Date startDate,
			Date endDate) {
		List<PerformanceView> result = new ArrayList<PerformanceView>();
		SearchCondition con = SearchCondition.newBuilder();
		con.add("startTime", SearchConditionComparator.LEFTBETWEEN, startDate, endDate);
		con.add("applicationId", SearchConditionComparator.EQUALS, applicationId);
		con.add("serviceId", SearchConditionComparator.IN, serviceIds.toArray());
		
		TermsBuilder termBuilder = AggregationUtil.getTerms("typeName", "typeName", Integer.MAX_VALUE);
		TermsBuilder tb = AggregationUtil.getTerms("serviceId", "serviceId", Integer.MAX_VALUE);
		TermsBuilder subTb = AggregationUtil.getTerms("channelName", "channelName", Integer.MAX_VALUE);
		subTb.subAggregation(AggregationUtil.getCount("count", "_index")); // 交易量
		subTb.subAggregation(AggregationUtil.getAvg("responseTime", "responseTime"));
		subTb.subAggregation(AggregationUtil.getFilter("isError", "isError", "true"));
		
		tb.subAggregation(AggregationUtil.getCount("count", "_index")); // 交易量
		tb.subAggregation(AggregationUtil.getAvg("responseTime", "responseTime"));
		tb.subAggregation(AggregationUtil.getFilter("isError", "isError", "true"));

		tb.subAggregation(subTb);
		termBuilder.subAggregation(tb);
		
		PagingList<PerformanceView> page = null;
		try {
			page = queryPerfService.querySubAggregationData(con.add(termBuilder));
		} catch (ApmDataIndicatorException e) {
			log.error("查询性能数据失败：" + e.getMessage());
		}
		if (page != null ) {
			result = page.getData();
		}
		return result;
	}

	@Override
	public List<PerformanceView> getTopTradeType(String subTermBy, int top, Date startDate, Date endDate, Set<String> appIdsSet) {
		List<PerformanceView> result = new ArrayList<PerformanceView>();
		SearchCondition con = SearchCondition.newBuilder();
		con.add("startTime", SearchConditionComparator.LEFTBETWEEN, startDate, endDate);
		con.add("applicationId", SearchConditionComparator.IN, appIdsSet.toArray());
		TermsBuilder termBuilder = AggregationUtil.getTerms("typeName", "typeName", Integer.MAX_VALUE);
		TermsBuilder tb = AggregationUtil.getTerms("serviceId", "serviceId", Integer.MAX_VALUE);
		TermsBuilder subTb = AggregationUtil.getTerms(subTermBy, subTermBy, Integer.MAX_VALUE);
		subTb.subAggregation(AggregationUtil.getCount("count", "_index")); // 交易量
		subTb.subAggregation(AggregationUtil.getAvg("responseTime", "responseTime"));
		subTb.subAggregation(AggregationUtil.getMax("responseTime_max", "responseTime"));
		subTb.subAggregation(AggregationUtil.getMin("responseTime_min", "responseTime"));
		subTb.subAggregation(AggregationUtil.getFilter("isError", "isError", "true"));
		subTb.subAggregation(AggregationUtil.getFilter("apdex_satisfied", "apdexFlag", "satisfaction"));
		subTb.subAggregation(AggregationUtil.getFilter("apdex_tolerate", "apdexFlag", "tolerate"));
		subTb.subAggregation(AggregationUtil.getFilter("apdex_unsatisfied", "apdexFlag", "unsatisfaction"));
		tb.subAggregation(AggregationUtil.getCount("count", "_index")); // 交易量
		tb.subAggregation(AggregationUtil.getAvg("responseTime", "responseTime"));
		tb.subAggregation(AggregationUtil.getMax("responseTime_max", "responseTime"));
		tb.subAggregation(AggregationUtil.getMin("responseTime_min", "responseTime"));
		tb.subAggregation(AggregationUtil.getFilter("isError", "isError", "true"));
		tb.subAggregation(AggregationUtil.getFilter("apdex_satisfied", "apdexFlag", "satisfaction"));
		tb.subAggregation(AggregationUtil.getFilter("apdex_tolerate", "apdexFlag", "tolerate"));
		tb.subAggregation(AggregationUtil.getFilter("apdex_unsatisfied", "apdexFlag", "unsatisfaction"));
//		subTb.order(Order.aggregation("isError", false));
		tb.subAggregation(subTb);
		termBuilder.subAggregation(tb);
		PagingList<PerformanceView> page = null;
		try {
			page = queryPerfService.querySubAggregationData(con.add(termBuilder));
		} catch (ApmDataIndicatorException e) {
			log.error("查询性能数据失败：" + e.getMessage());
		}
		if (page != null ) {
			result = page.getData();
		}
		return result;
	}

}
